/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Discribe：实现定时器
* CreateTime：2020-04-05 20:21:58
* Version：1.0
* Modify Recoder：
*************************************************/
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace TinyToolKit.Timer
{
    public class TTimerManager :ManagerBase
    {
        private const string Obj = "LOCK";
        private int _id;
        private List<int> _taskIdList; //任务ID列表
        private List<int> _releaseTaskIdList;//暂存已经完成的任务

        private List<TimerTask> _tempTimerList;//暂存临时添加的任务
        public List<TimerTask> TaskTimerList { get; private set; }

        public int CurFrameCount { get; private set; }
        private List<TimerTaskByFrame> _tempFrameList;
        public List<TimerTaskByFrame> TaskFrameList { get; private set; }

        #region Manager Base
        public override void Init()
        {
            _taskIdList = new List<int>();
            _releaseTaskIdList = new List<int>();
            _tempTimerList = new List<TimerTask>();
            TaskTimerList = new List<TimerTask>();
            _tempFrameList = new List<TimerTaskByFrame>();
            TaskFrameList = new List<TimerTaskByFrame>();
        }

        public override void UpdateManager()
        {
            CheakTimerTask();
            CheakTimerTaskByFrame();

            if (_releaseTaskIdList.Count <= 0) return;
            RecycleTaskTD();
            _releaseTaskIdList.Clear();
        }

        //在场景切换的时候，删除所有计时任务
        public override void OnSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            DeleteAllTasks();
        }

        public override void Shutdown()
        {
            _taskIdList.Clear();
            _releaseTaskIdList.Clear();
            _tempTimerList.Clear();
            TaskTimerList.Clear();
            _tempFrameList.Clear();
            TaskFrameList.Clear();
        }
        #endregion

        #region Cheak Timer Task
        /// <summary>
        /// 检查定时任务是否到达执行时间
        /// </summary>
        private void CheakTimerTask()
        {
            //加入存在缓存区的定时任务
            for (int tempIndex = 0; tempIndex < _tempTimerList.Count; tempIndex++)
            {
                TaskTimerList.Add(_tempTimerList[tempIndex]);
            }
            _tempTimerList.Clear();

            for (int index = 0; index < TaskTimerList.Count; index++)
            {
                TimerTask task = TaskTimerList[index];
                //过滤所有非运行状态的定时任务
                if(task.taskState != TaskState.Running)
                {
                    task.destTime += GetDeltaTime(task.ignoreTimeScale); 
                    continue;    
                }

                if (GetTime(task.ignoreTimeScale) < task.destTime) 
                {
                    continue;
                }
                else
                {
                    if (task.repeatCount == 1)
                    {
                        //移除已经完成的任务
                        TaskTimerList.RemoveAt(index);
                        index--;
                        _releaseTaskIdList.Add(task.taskID);
                    }
                    else
                    {
                        if (task.repeatCount != 0)
                            task.repeatCount--;

                        task.destTime += task.duration;
                    }

                    var cb = task?.callback;
                    cb?.Invoke();
                }
            }
        }

        /// <summary>
        /// 检查帧定时任务是否到达执行时间
        /// </summary>
        private void CheakTimerTaskByFrame()
        {
            //frameCounter = Time.frameCount;
            CurFrameCount ++;
            //加入缓存区的定时任务
            for (int tempIndex = 0; tempIndex < _tempFrameList.Count; tempIndex++)
            {
                TaskFrameList.Add(_tempFrameList[tempIndex]);
            }
            _tempFrameList.Clear();

            for (int index = 0; index < TaskFrameList.Count; index++)
            {
                TimerTaskByFrame task = TaskFrameList[index];
                //过滤所有非运行状态的定时任务
                if (task.taskState != TaskState.Running) 
                {
                    task.destFrame++;
                    continue;
                }

                if (CurFrameCount < task.destFrame)
                {
                    continue;
                }
                else
                {
                    if (task.repeatCount == 1)
                    {
                        //移除已经完成的任务
                        TaskFrameList.RemoveAt(index);
                        index--;
                        _releaseTaskIdList.Add(task.taskID);
                    }
                    else
                    {
                        if (task.repeatCount != 0)
                            task.repeatCount--;

                        task.destFrame += task.frameCount;
                    }

                    try
                    {
                        Action cb = task.callback;
                        if (cb != null)
                            cb();
                    }
                    catch (Exception e)
                    {
                        TLogTool.Error("【异常】：" + e.ToString());
                    }
                }
            }
        }
        #endregion

        #region Time Task

        /// <summary>
        /// 添加定时任务
        /// </summary>
        /// <param name="callback">回调方法</param>
        /// <param name="duration">延迟时间</param>
        /// <param name="timerUnit">时间单位，默认秒</param>
        /// <param name="repeatCount">重复执行次数，0表示循环</param>
        /// <param name="ignoreTimeScale">是否忽略TimeScale的影响</param>
        public int AddTimerTask(Action callback,float duration, int repeatCount = 1, TimerUnit timerUnit = TimerUnit.Second,bool ignoreTimeScale = false)
        {
            duration = ConvertToSeconds(duration, timerUnit);

            int taskId = GetID();
            float destTime = GetTime(ignoreTimeScale) + duration;
            TimerTask timeTask = new TimerTask(taskId, callback, destTime, duration, repeatCount,ignoreTimeScale);
            _tempTimerList.Add(timeTask);
            _taskIdList.Add(taskId);

            return taskId;
        }

        /// <summary>
        /// 按照一定的时间间隔，执行一定的次数
        /// </summary>
        /// <typeparam name="T">回调的参数类型</typeparam>
        /// <param name="callBack">执行的回调</param>
        /// <param name="obj">回调的参数</param>
        /// <param name="interval">执行的时间间隔</param>
        /// <param name="repeatCount">执行的次数</param> 
        /// <returns>返回任务ID</returns>
        public int AddTimerTask<T>(Action<T> callBack,T obj, float duration, int repeatCount = 1)
        {
            return AddTimerTask(() =>
            {
                if (callBack != null)
                    callBack.Invoke(obj);
            }, duration, repeatCount, TimerUnit.Second);
        }

        /// <summary>
        /// 暂停定时任务
        /// </summary>
        /// <returns><c>true</c>, 定时任务被暂停, <c>false</c> 未被暂停</returns>
        /// <param name="taskID">任务ID</param>
        public bool PauseTimerTask(int taskID)
        {
            bool isFind = false;
            for (int i = 0; i < TaskTimerList.Count; i++)
            {
                if (TaskTimerList[i].taskID == taskID)
                {
                    TaskTimerList[i].taskState = TaskState.Paused;
                    isFind = true;
                    break;
                }
            }

            if (isFind == false)
            {
                for (int i = 0; i < _tempTimerList.Count; i++)
                {
                    if (_tempTimerList[i].taskID == taskID)
                    {
                        _tempTimerList[i].taskState = TaskState.Paused;
                        isFind = true;
                        break;
                    }
                }
            }

            return isFind;
        }

        /// <summary>
        /// 恢复定时任务
        /// </summary>
        /// <returns><c>true</c>, 定时任务被恢复, <c>false</c>未被恢复</returns>
        /// <param name="taskID">任务ID</param>
        public bool ResumeTimerTask(int taskID)
        {
            bool isFind = false;
            for (int i = 0; i < TaskTimerList.Count; i++)
            {
                if (TaskTimerList[i].taskID == taskID)
                {
                    TaskTimerList[i].taskState = TaskState.Running;
                    isFind = true;
                    break;
                }
            }

            if (isFind == false)
            {
                for (int i = 0; i < _tempTimerList.Count; i++)
                {
                    if (_tempTimerList[i].taskID == taskID)
                    {
                        _tempTimerList[i].taskState = TaskState.Running;
                        isFind = true;
                        break;
                    }
                }
            }

            return isFind;
        }

        /// <summary>
        /// 根据任务ID，删除对应的定时任务
        /// </summary>
        /// <returns><c>true</c>, 定时任务被删除 <c>false</c> 为被删除</returns>
        /// <param name="taskID">任务ID</param>
        public bool DeleteTimerTask(int taskID)
        {
            bool exist = false;

            for (int i = 0; i < TaskTimerList.Count; i++)
            {
                TimerTask tempTask = TaskTimerList[i];
                if (tempTask.taskID == taskID)
                {
                    TaskTimerList.RemoveAt(i);
                    for (int j = 0; j < _taskIdList.Count; j++)
                    {
                        if (_taskIdList[j] == taskID)
                        {
                            _taskIdList.RemoveAt(j);
                            break;
                        }
                    }
                    exist = true;
                    break;
                }
            }

            if (exist == false)
            {
                for (int i = 0; i < _tempTimerList.Count; i++)
                {
                    TimerTask tempTask = _tempTimerList[i];
                    if (tempTask.taskID == taskID)
                    {
                        _tempTimerList.RemoveAt(i);
                        for (int j = 0; j < _taskIdList.Count; j++)
                        {
                            if (_taskIdList[j] == taskID)
                            {
                                _taskIdList.RemoveAt(j);
                                break;
                            }
                        }
                        exist = true;
                        break;
                    }
                }
            }

            return exist;
        }

        /// <summary>
        /// 根据任务ID，替换新的定时任务
        /// </summary>
        /// <returns><c>true</c>, 定时任务被成功替换, <c>false</c> 未被成功替换</returns>
        /// <param name="taskId">任务ID</param>
        /// <param name="callback">新定时任务完成时的回调</param>
        /// <param name="duration">新定时任务的延迟时间</param>
        /// <param name="timerUnit">时间单位</param>
        /// <param name="repeatCount">新定时任务的重复次数</param>
        /// <param name="ignoreTimeScale">是否忽略TimeScale的影响</param>
        public bool ReplaceTimerTask(int taskId, Action callback, float duration, int repeatCount = 1, TimerUnit timerUnit = TimerUnit.Second,bool ignoreTimeScale = false)
        {
            duration = ConvertToSeconds(duration, timerUnit);

            float destTime = GetTime(ignoreTimeScale) + duration;
            TimerTask newTimerTask = new TimerTask(taskId, callback, destTime, duration, repeatCount,ignoreTimeScale);
            bool isReplace = false;
            for (int i = 0; i < TaskTimerList.Count; i++)
            {
                if (TaskTimerList[i].taskID == taskId)
                {
                    TaskTimerList[i] = newTimerTask;
                    isReplace = true;
                    break;
                }
            }

            if (isReplace == false)
            {
                for (int i = 0; i < _tempTimerList.Count; i++)
                {
                    if (_tempTimerList[i].taskID == taskId)
                    {
                        _tempTimerList[i] = newTimerTask;
                        isReplace = true;
                        break;
                    }
                }
            }

            return isReplace;
        }
        #endregion

        #region Frame Task
        /// <summary>
        /// 添加帧定时任务
        /// </summary>
        /// <returns>返回定时任务的任务ID</returns>
        /// <param name="callback">定时任务完成时的回调函数</param>
        /// <param name="frameCount">定时任务的延迟帧数</param>
        /// <param name="repeatCount">定时任务的重复次数，0表示循环</param>
        public int AddTimeTaskByFrame(Action callback, int frameCount, int repeatCount = 1)
        {
            int taskID = GetID();
            TimerTaskByFrame frameTask = new TimerTaskByFrame(taskID, callback, CurFrameCount + frameCount, frameCount, repeatCount);
            _tempFrameList.Add(frameTask);
            _taskIdList.Add(taskID);
            return taskID;
        }

        /// <summary>
        /// 添加帧定时任务事件
        /// </summary>
        /// <typeparam name="T">回调参数的类型</typeparam>
        /// <param name="callBack">帧定时任务完成时的回调函数</param>
        /// <param name="obj">需要回调的参数</param>
        /// <param name="frameCount">帧定时任务的延迟帧数</param>
        /// <param name="repeatCount">帧定时任务的循环次数，0表示循环</param>
        /// <returns>任务ID</returns> 
        public int AddTimeTaskByFrame<T>(Action<T> callBack,T obj,int frameCount, int repeatCount = 1)
        {
            return AddTimeTaskByFrame(() =>
            {
                if (callBack != null)
                    callBack.Invoke(obj);
            }, frameCount, repeatCount);
        }

        /// <summary>
        /// 暂停帧定时任务
        /// </summary>
        /// <returns><c>true</c>, 帧定时任务暂停成功, <c>false</c> 暂停失败</returns>
        /// <param name="taskID">需要暂停的帧定时任务ID</param>
        public bool PauseTimerTaskByFrame(int taskID)
        {
            bool isFind = false;
            for (int i = 0; i < TaskFrameList.Count; i++)
            {
                if (TaskFrameList[i].taskID == taskID)
                {
                    TaskFrameList[i].taskState = TaskState.Paused;
                    isFind = true;
                    break;
                }
            }

            if (isFind == false)
            {
                for (int i = 0; i < _tempFrameList.Count; i++)
                {
                    if (_tempFrameList[i].taskID == taskID)
                    {
                        _tempFrameList[i].taskState = TaskState.Paused;
                        isFind = true;
                        break;
                    }
                }
            }

            return isFind;
        }

        /// <summary>
        /// 恢复暂停的帧定时任务
        /// </summary>
        /// <returns><c>true</c>, 暂停的帧定时任务恢复成功, <c>false</c> 恢复失败</returns>
        /// <param name="taskID">需要恢复的帧定时任务ID</param>
        public bool ResumeTimerTaskByFrame(int taskID)
        {
            bool isFind = false;
            for (int i = 0; i < TaskFrameList.Count; i++)
            {
                if (TaskFrameList[i].taskID == taskID)
                {
                    TaskFrameList[i].taskState = TaskState.Running;
                    isFind = true;
                    break;
                }
            }

            if (isFind == false)
            {
                for (int i = 0; i < _tempFrameList.Count; i++)
                {
                    if (_tempFrameList[i].taskID == taskID)
                    {
                        _tempFrameList[i].taskState = TaskState.Running;
                        isFind = true;
                        break;
                    }
                }
            }

            return isFind;
        }

        /// <summary>
        /// 根据任务ID，删除对应的定时任务
        /// </summary>
        /// <returns><c>true</c>, 删除帧定时任务成功, <c>false</c> 删除失败</returns>
        /// <param name="taskID">帧定时任务ID</param>
        public bool DeleteTimerTaskByFrame(int taskID)
        {
            bool exist = false;

            for (int i = 0; i < TaskFrameList.Count; i++)
            {
                TimerTaskByFrame tempTask = TaskFrameList[i];
                if (tempTask.taskID == taskID)
                {
                    TaskFrameList.RemoveAt(i);
                    for (int j = 0; j < _taskIdList.Count; j++)
                    {
                        if (_taskIdList[j] == taskID)
                        {
                            _taskIdList.RemoveAt(j);
                            break;
                        }
                    }
                    exist = true;
                    break;
                }
            }

            if (exist == false)
            {
                for (int i = 0; i < _tempFrameList.Count; i++)
                {
                    TimerTaskByFrame tempTask = _tempFrameList[i];
                    if (tempTask.taskID == taskID)
                    {
                        _tempFrameList.RemoveAt(i);
                        for (int j = 0; j < _taskIdList.Count; j++)
                        {
                            if (_taskIdList[j] == taskID)
                            {
                                _taskIdList.RemoveAt(j);
                                break;
                            }
                        }
                        exist = true;
                        break;
                    }
                }
            }

            return exist;
        }
         
        /// <summary>
        /// 根据任务ID，替换帧定时任务
        /// </summary>
        /// <returns><c>true</c>, 替换帧定时任务成功, <c>false</c> 替换失败</returns>
        /// <param name="taskID">需要替换的帧定时任务的ID</param>
        /// <param name="callback">替换的帧定时任务的回调函数</param>
        /// <param name="frameCount">替换的帧定时任务的延迟帧数</param>
        /// <param name="repeatCount">替换的帧定时任务的重复次数</param>
        public bool ReplaceTimerTaskByFrame(int taskID, Action callback, int frameCount, int repeatCount = 1)
        {
            TimerTaskByFrame newFrameTask = new TimerTaskByFrame(taskID, callback, CurFrameCount + frameCount, frameCount, repeatCount);

            bool isReplace = false;
            for (int i = 0; i < TaskFrameList.Count; i++)
            {
                if (TaskFrameList[i].taskID == taskID)
                {
                    TaskFrameList[i] = newFrameTask;
                    isReplace = true;
                    break;
                }
            }

            if (isReplace == false)
            {
                for (int i = 0; i < _tempFrameList.Count; i++)
                {
                    if (_tempFrameList[i].taskID == taskID)
                    {
                        _tempFrameList[i] = newFrameTask;
                        isReplace = true;
                        break;
                    }
                }
            }

            return isReplace;
        }
        #endregion

        #region Tool Methods
        public void DeleteAllTasks()
        {
            for (int i = 0; i < TaskTimerList.Count; i++)
            {
                DeleteTimerTask(TaskTimerList[i].taskID); 
            }
            TaskTimerList.Clear();
            
            for (int i = 0; i < _tempTimerList.Count; i++)    
            {
                DeleteTimerTask(_tempTimerList[i].taskID); 
            }
            _tempTimerList.Clear();
            
            for (int i = 0; i < TaskFrameList.Count; i++)
            {
                DeleteTimerTaskByFrame(TaskFrameList[i].taskID);
            }
            TaskFrameList.Clear(); 
            
            for (int i = 0; i < _tempFrameList.Count; i++)    
            {
                DeleteTimerTaskByFrame(_tempFrameList[i].taskID); 
            }
            _tempFrameList.Clear();  
        }

        /// <summary>
        /// 根据任务ID，获取任务的状态
        /// </summary>
        public TaskState GetTaskState(int taskID)
        {
            for (int i = 0; i < TaskTimerList.Count; i++)
            {
                if (TaskTimerList[i].taskID == taskID)
                {
                    return TaskTimerList[i].taskState;
                }
            }

            for (int i = 0; i < _tempTimerList.Count; i++)
            {
                if (_tempTimerList[i].taskID == taskID)
                {
                    return _tempTimerList[i].taskState;
                }
            }
            return TaskState.None;
        }

        /// <summary>
        /// 根据任务ID，获取帧定时任务的状态
        /// </summary>
        public TaskState GetTaskStateByFrame(int taskID)
        {
            for (int i = 0; i < TaskFrameList.Count; i++)
            {
                if (TaskFrameList[i].taskID == taskID)
                {
                    return TaskFrameList[i].taskState;
                }
            }

            for (int i = 0; i < _tempFrameList.Count; i++)
            {
                if (_tempFrameList[i].taskID == taskID)
                {
                    return _tempFrameList[i].taskState;
                }
            }
            return TaskState.None;
        }

        /// <summary>
        /// 将其他时间类型转化为秒数
        /// </summary>
        /// <returns>The to seconds.</returns>
        /// <param name="duration">当前的时间的间隔</param>
        /// <param name="timerUnit">当前时间的类型</param>
        private float ConvertToSeconds(float duration, TimerUnit timerUnit)
        {
            switch (timerUnit)
            {
                case TimerUnit.Millisecond:
                    duration = duration / 1000;
                    break;
                case TimerUnit.Minute:
                    duration = duration * 60;
                    break;
                case TimerUnit.Hour:
                    duration = duration * 60 * 60;
                    break;
                case TimerUnit.Day:
                    duration = duration * 60 * 60 * 24;
                    break;
            }

            return duration;
        }

        /// <summary>
        /// 生成定时任务的全局ID
        /// </summary>
        /// <returns>返回任务ID</returns>
        private int GetID()
        {
            lock (Obj)
            {
                _id += 1;

                while (true)
                {
                    if (_id >= int.MaxValue)
                        _id = 0;

                    bool used = false;
                    for (int i = 0; i < _taskIdList.Count; i++)
                    {
                        if (_id == _taskIdList[i])
                        {
                            used = true;
                            break;
                        }
                    }

                    if (used == false)
                        break;
                    else
                        _id++;
                }
            }
            return _id;
        }

        /// <summary>
        /// 回收任务ID
        /// </summary>
        private void RecycleTaskTD()
        {
            for (int i = 0; i < _releaseTaskIdList.Count; i++)
            {
                int id = _releaseTaskIdList[i];

                for (int j = 0; j < _taskIdList.Count; j++)
                {
                    if (_taskIdList[j] == id)
                    {
                        _taskIdList.RemoveAt(j);
                        break;
                    }
                }
            }
        }

        private float GetDeltaTime(bool ignoreTimeScale)
        {
            return ignoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime;
        }

        private float GetTime(bool ignoreTimeScale) 
        {
            return ignoreTimeScale ? Time.realtimeSinceStartup : Time.time;
        }

        #endregion
    }
}

